package handle

import (
	g "blog.wuzhispace.com/internal/global"
	"blog.wuzhispace.com/internal/model"
	"blog.wuzhispace.com/internal/utils"
	"blog.wuzhispace.com/internal/utils/jwt"
	"errors"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"golang.org/x/exp/slog"
	"gorm.io/gorm"
	"strconv"
)

type UserAuth struct {
}
type LoginReq struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

type RegisterReq struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required,min=6,max=20"`
	Code     string `json:"code" binding:"required"`
}
type LoginVO struct {
	model.UserInfo

	// 点赞 Set: 用于记录用户点赞过的文章, 评论
	ArticleLikeSet []string `json:"article_like_set"`
	CommentLikeSet []string `json:"comment_like_set"`
	Token          string   `json:"token"`
}

func (*UserAuth) Register(c *gin.Context) {
	ReturnSuccess(c, "注册")
}

func (*UserAuth) Login(c *gin.Context) {
	var req LoginReq
	if err := c.ShouldBindJSON(&req); err != nil {
		ReturnError(c, g.ErrRequest, nil)
		return
	}
	db := GetDB(c)
	rdb := GetRDB(c)
	// 查询用户是否存在
	userAuth, err := model.GetUserAuthInfoByName(db, req.Username)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			ReturnError(c, g.ErrUserNotExist, nil)
			return
		}
		ReturnError(c, g.ErrDbOp, nil)
		return
	}
	// 验证密码
	if !utils.BcryptCheck(req.Password, userAuth.Password) {
		ReturnError(c, g.ErrPassword, nil)
		return
	}
	// 获取 IP 相关信息
	ipAddress := utils.IP.GetIpAddress(c)
	ipSource := utils.IP.GetIpSourceSimpleIdle(ipAddress)

	userInfo, err := model.GetUserInfoById(db, userAuth.UserInfoId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			ReturnError(c, g.ErrUserNotExist, nil)
			return
		}
		ReturnError(c, g.ErrDbOp, nil)
		return
	}
	roleIds, err := model.GetRoleIdsByUserId(db, userAuth.ID)
	if err != nil {
		ReturnError(c, g.ErrDbOp, nil)
		return
	}
	// 验证通过后，生成token，并返回给前端
	// 登录信息正确, 生成 Token
	conf := g.Conf.JWT
	token, err := jwt.GenToken(conf.Secret, conf.Issuer, int(conf.Expire), userAuth.ID, roleIds)
	if err != nil {
		ReturnError(c, g.ErrTokenCreate, nil)
		return
	}
	// 更新用户验证信息: ip 信息 + 上次登录时间
	err = model.UpdateUserLoginInfo(db, userAuth.ID, ipAddress, ipSource)
	if err != nil {
		ReturnError(c, g.ErrDbOp, nil)
		return
	}

	slog.Info("用户登录成功: " + userAuth.Username)
	session := sessions.Default(c)
	session.Set(g.CTX_USER_AUTH, userAuth.ID)
	session.Save()

	// 删除redis中的离线状态
	offlineKey := g.OFFLINE_USER + strconv.Itoa(userAuth.ID)
	rdb.Del(rctx, offlineKey)
	// 保存token到redis中，并设置过期时间
	// 返回登录成功的信息
	ReturnSuccess(c, LoginVO{
		Token:          token,
		UserInfo:       *userInfo,
		ArticleLikeSet: []string{},
		CommentLikeSet: []string{},
	})
}

func (*UserAuth) Logout(c *gin.Context) {
	c.Set(g.CTX_USER_AUTH, nil)

	// 已经退出登录了
	auth, _ := CurrentUserAuth(c)
	if auth == nil {
		ReturnSuccess(c, "退出登录")
	}
	// 删除session
	session := sessions.Default(c)
	session.Delete(g.CTX_USER_AUTH)
	session.Save()

	// 删除redis中的在线状态
	rdb := GetRDB(c)
	onlineKey := g.ONLINE_USER + strconv.Itoa(auth.ID)
	rdb.Del(rctx, onlineKey)
	ReturnSuccess(c, "登出")
}
